A genetic algorithm (GA) is a computational technique inspired by natural selection and genetics. It begins with a population of potential solutions to a problem, represented as "chromosomes" with specific characteristics. Each solution's fitness is evaluated, and individuals are selected for reproduction based on their fitness. Through crossover (combining genetic information from parents) and mutation (randomly altering genes), new offspring are generated. The offspring, along with some individuals from the previous generation, form the next population. This iterative process continues, with better-fit solutions surviving and potentially evolving to optimize the problem over successive generations. GAs are widely used for optimization and search in various domains, seeking approximate solutions efficiently in complex and diverse solution spaces.
import numpy as np
# Define the fitness function to be optimized
def fitness_function(x):
return -x**2 # We want to find the maximum of this function
# Genetic algorithm parameters
population_size = 20
chromosome_length = 5
mutation_rate = 0.1
crossover_rate = 0.8
num_generations = 100
# Generate an initial population with random chromosomes
def initialize_population(population_size, chromosome_length):
return np.random.randint(2, size=(population_size, chromosome_length))
# Decode the binary chromosome to a decimal value
def decode_chromosome(chromosome):
return int(''.join([str(bit) for bit in chromosome]), 2)
# Calculate fitness for each individual in the population
def calculate_fitness(population):
return np.array([fitness_function(decode_chromosome(chromosome)) for chromosome in population])
# Perform single-point crossover between two parent chromosomes
def crossover(parent1, parent2):
crossover_point = np.random.randint(1, len(parent1) - 1)
child1 = np.concatenate((parent1[:crossover_point], parent2[crossover_point:]))
child2 = np.concatenate((parent2[:crossover_point], parent1[crossover_point:]))
return child1, child2
# Perform mutation on a chromosome
def mutate(chromosome):
for i in range(len(chromosome)):
if np.random.rand() < mutation_rate:
chromosome[i] = 1 - chromosome[i]
return chromosome
# Genetic algorithm
def genetic_algorithm(population_size, chromosome_length, mutation_rate, crossover_rate, num_generations):
population = initialize_population(population_size, chromosome_length)
for generation in range(num_generations):
fitness_values = calculate_fitness(population)
# Select parents for crossover
parents = population[np.random.choice(population_size, size=population_size, replace=True, p=fitness_values / np.sum(fitness_values))]
# Perform crossover and mutation
for i in range(0, population_size, 2):
if np.random.rand() < crossover_rate:
population[i], population[i + 1] = crossover(parents[i], parents[i + 1])
population[i] = mutate(population[i])
population[i + 1] = mutate(population[i + 1])
best_individual = population[np.argmax(fitness_values)]
best_value = decode_chromosome(best_individual)
return best_value
# Run the genetic algorithm
best_solution = genetic_algorithm(population_size, chromosome_length, mutation_rate, crossover_rate, num_generations)
print("Best solution found:", best_solution)
print("Fitness value of best solution:", fitness_function(best_solution))